#define EPSILON.001
#define MAX_DIST 200.
// 用更大的迭代次数保证最远处不隆起
#define MAX_ITER 300

// 2D Random
float random(in vec2 st){
  return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);
}

// 2D Noise based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float noise(in vec2 st){
  vec2 i=floor(st);
  vec2 f=fract(st);
  
  // Four corners in 2D of a tile
  float a=random(i);
  float b=random(i+vec2(1.,0.));
  float c=random(i+vec2(0.,1.));
  float d=random(i+vec2(1.,1.));
  
  // Smooth Interpolation
  
  // Cubic Hermine Curve.  Same as SmoothStep()
  vec2 u=f*f*(3.-2.*f);
  // u = smoothstep(0.,1.,f);
  
  // Mix 4 coorners percentages
  return mix(a,b,u.x)+
  (c-a)*u.y*(1.-u.x)+
  (d-b)*u.x*u.y;
}

vec2 fixUV(vec2 cood){
  return(2.*cood.xy-iResolution.xy)/min(iResolution.x,iResolution.y);
}

float ground(vec2 p){
  return 2.*noise(p);
}

float rayMarch(vec3 ro,vec3 rd){
  float t=0.;
  for(int i=0;i<MAX_ITER;i++){
    vec3 p=ro+t*rd;
    float h=p.y-ground(p.xz);
    // EPSILON * t 设置EPSILON精度由近到远变低，提高渲染效率
    if(abs(h)<EPSILON*t||t>MAX_DIST){
      break;
    }
    // t+=h;
    // 解决拉伸后瑕疵
    t+=.2*h;
  }
  return t;
}

vec3 calcNorm(vec3 p){
  vec2 epsilon=vec2(1e-5,0);
  return normalize(vec3(
      ground(p.xz+epsilon.xy)-ground(p.xz-epsilon.xy),
      2.*epsilon.x,
      ground(p.xz+epsilon.yx)-ground(p.xz-epsilon.yx)
    )
  );
}

mat3 setCamera(vec3 ro,vec3 target,float cr){
  vec3 z=normalize(target-ro);
  vec3 up=normalize(vec3(sin(cr),cos(cr),0));
  vec3 x=cross(z,up);
  vec3 y=cross(x,z);
  return mat3(x,y,z);
}

vec3 render(vec2 uv){
  vec3 col=vec3(0.);
  
  float an=.2*iTime;
  float r=10.;
  vec3 ro=vec3(r*sin(an),5,r*cos(an));
  vec3 target=vec3(0,0,10);
  mat3 cam=setCamera(ro,target,0.);
  
  float fl=1.;
  vec3 rd=normalize(cam*vec3(uv,fl));
  
  float t=rayMarch(ro,rd);
  
  if(t<MAX_DIST){
    vec3 p=ro+t*rd;
    vec3 n=calcNorm(p);
    vec3 difColor=vec3(.9,.8,0.);
    col=.2+.8*difColor*dot(n,vec3(0,1,0));
  }
  
  // return sqrt(col);
  return col;
}

void mainImage(out vec4 fragColor,in vec2 fragCoord){
  vec2 uv=fixUV(fragCoord);
  vec3 color=render(uv);
  fragColor=vec4(color,1.);
}